'I2c2 System I2C bus must be established
'The SUBS can be added to Basic programs to replace the LCD print commands. 
'They could also be adapted and added to the Library e.g. PLCD line, pos, data$

l_data = 0
cursorline = 0
cursorpos = 0
charloc = 0
textstring$ = ""

do				'List menu options
  cls
  print "1 - Initialise LCD"
  Print "2 - Backlight on"
  Print "3 - Backlight off"
  print "4 - Clear display"
  print "5 - Send character"
  print "6 - Home cursor"
  print "7 - Set cursor position"
  print "8 - Print string"
  Print "0 - Quit"

  Input selection

  select case selection
    case 1 
    	print "initialising PLCD"
    	send_ctrl(3)            'force 0011 to set 8-bit i/face 3 times as 4-bit transfers
    	send_ctrl(3)     
  
    	send_ctrl(3)

    	send_ctrl(2)            'send 0010 to set 4-bit i/face once as final 4-bit t

    	send_ctrl(2)            'send 0010 10xx for  Funstion Set
    	send_ctrl(8)            '4-bit i/face (undisturbed), 2 lines, 5x8 chars
    
    	send_ctrl(0)            'send 0000 1100 for Display Control
    	send_ctrl(12)           'display on, cursor off, blink off
    
    	send_ctrl(0)            'send 0000 0001 Clear Display
    	send_ctrl(1)
    
    	send_ctrl(0)            'send 0000 0111 Increment DDRAM, no shift
    	send_ctrl(6)
    
    	send_ctrl(0)            'send 0000 0010 Home cursor
    	send_ctrl(2)
  
    case 2 
	PLCD_lon()		'turn on backlight
  
    case 3 
	PLCD_loff()		'turn off backlight
  
    case 4
    	send_ctrl(0)		'clear display
    	send_ctrl(1)

    	pause 10

    	send_ctrl(0)
    	send_ctrl(2)

    case 5			'Sends a single character "H" to the display
    	send_char("H")
  
    case 6			'moves the cursor to 1st position, 1st line
    	send_ctrl(0)		
    	send_ctrl(2)

    case 7
    	input "Enter Position: ", cursorpos
    	move_cursor(cursorpos)

    case 8     			'this mimics the LCD command in MMBasic
	input "Enter line: ", cursorline

    	if cursorline > 3 then 
      	  cursorline = 3
    	end if
    
    	input "Enter start position (0-19): ", cursorpos
    	if cursorpos > 19 then
      	  cursorpos = 19
    	end if
    
    	input "Enter string: ", textstring$
    	select case cursorline
      	  case 1
            cursorpos = cursorpos + &h40  'start posn 1st row in hex
      	  case 2
            cursorpos = cursorpos + &h14  'start posn 2nd row in hex
      	  case 3
            cursorpos = cursorpos + &h54  'start posn 3rd row in hex
      	  case else			'leave posn of 0th row
    	end select
 
    	move_cursor(cursorpos)
     
    	for charloc = 1 to len(textstring$) 'relies on LCD autoincrementing cursor posn
      	  send_char(mid$(textstring$,charloc,1))
    	next charloc
 
    case 0			'End demo
	end

  end select

loop

 
Sub PLCD_lon()
    I2C2 write 62,0,1,8
End Sub


Sub PLCD_loff()
    I2C2 write 62,0,1,0
End Sub


sub send_ctrl(l_data)
    local lcd_temp
    i2c2 read 62,0,1,lcd_temp
    lcd_temp = lcd_temp AND &B00001110  'mask the 4 control bits, clearing RS to
    l_data = l_data<<4                'shift data to upper 4 bits
    l_data = l_data OR lcd_temp
    write_plcd_ctrl(l_data)
    l_data = 0
end sub


    
sub send_char(l_data$)
    local lcd_temp = 0
    lcd_temp =asc(l_data$)
    write_plcd_data (lcd_temp)
    l_data$ = ""
end sub
  

    
sub write_plcd_ctrl(plcd_data)
    plcd_data = plcd_data AND &B11111000  'clear EN, R|/W and RS to CTRL register
    i2c2 write 62,0,1,plcd_data
    pause 1
    plcd_data = plcd_data OR &B00000100   'toggle E pin to write, 1 ms puls
    i2c2 write 62,0,1,plcd_data
    pause 1
    plcd_data = plcd_data AND &B11111000     'keeping b0-data off
    i2c2 write 62,0,1,plcd_data
    pause 1
end sub



sub write_plcd_data(plcd_data)      'takes 8-bit data, slices in to 2 x 4bits

    local lcd_u_nibble, lcd_l_nibble  'upper and lower nibbles
    
    i2c2 read 62,0,1,lcd_temp        'read current pin states on port
    
    lcd_temp = lcd_temp AND &B00001001  'clear EN and R|/W and set RS to DATA
    lcd_temp = lcd_temp OR &B00000001   'ensure set RS to DATA register

    lcd_u_nibble = plcd_data and &B11110000 'mask off upper data nibble
    lcd_l_nibble = plcd_data << 4

    plcd_data = lcd_u_nibble OR lcd_temp    'prep upper nibble 
    i2c2 write 62,0,1,plcd_data

    plcd_data = plcd_data OR &B00000100     'toggle E pin to write, 1 ms puls
    i2c2 write 62,0,1,plcd_data

    plcd_data = plcd_data AND &B11111001    'keeping b0-data on
    i2c2 write 62,0,1,plcd_data

    plcd_data = lcd_l_nibble OR lcd_temp    'prep lower nibble 
    i2c2 write 62,0,1,plcd_data

    plcd_data = plcd_data OR &B00000100     'toggle E pin to write, 1 ms puls
    i2c2 write 62,0,1,plcd_data

    plcd_data = plcd_data AND &B11111001    'keeping b0-data on
    i2c2 write 62,0,1,plcd_data
    
    pause 1			'better to check LCD busy flag, but this works OK
end sub


sub move_cursor(cursorpos)
    cursorposlow = cursorpos and &b00001111
    cursorposhigh = cursorpos or &B10000000 'set ctrl bit to DDRAM addr reg
    cursorposhigh = cursorposhigh >>4   'send upper nibble to lower nibble
    
    send_ctrl(cursorposhigh)
    send_ctrl(cursorposlow)
end sub  